/**
  ******************************************************************************
  * File Name          : can-ctrl.c
  * Description        : can-ctrl program body
  ******************************************************************************
  *
  * Copyright (c) 2019 HopeMotion Co., Ltd. 
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without 
  * modification, are permitted, provided that the following conditions are met:
  *
  * 1. Redistribution of source code must retain the above copyright notice, 
  *    this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright notice,
  *    this list of conditions and the following disclaimer in the documentation
  *    and/or other materials provided with the distribution.
  * 3. Neither the name of HopeMotion nor the names of other 
  *    contributors to this software may be used to endorse or promote products 
  *    derived from this software without specific written permission.
  * 4. This software, including modifications and/or derivative works of this 
  *    software, must execute solely and exclusively on microcontroller or
  *    microprocessor devices manufactured by or for HopeMotion.
  * 5. Redistribution and use of this software other than as permitted under 
  *    this license is void and will automatically terminate your rights under 
  *    this license. 
  *
  * THIS SOFTWARE IS PROVIDED BY HOPEMOTION AND CONTRIBUTORS "AS IS" 
  * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT 
  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
  * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
  * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT 
  * SHALL HOPEMOTION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 
  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <net/if.h>
#include <sys/times.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include "../include/zeus_x2_driver/can-ctrl.h"

#define INADEQUATE_CONDITIONS 	-1
#define WAIT_usDELAY			50
#define WAIT_TIMEOUT			5000

// #define  TEST

/* Private variables ---------------------------------------------------------*/
static int fdcan0;
static int fdcan1;

int fs_sel0;
fd_set  fs_read0;
struct timeval tv_timeout0;

int fs_sel1;
fd_set  fs_read1;
struct timeval tv_timeout1;

struct can_frame frame0_tx = { 
	.can_id = 0x304,
	.can_dlc = 8,
	.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};

struct can_frame frame0_rx = { 
	.can_id = 0x284,
	.can_dlc = 8,
	.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};

struct can_frame frame1_tx = { 
	.can_id = 0x301,
	.can_dlc = 8,
	.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};

struct can_frame frame1_rx = { 
	.can_id = 0x281,
	.can_dlc = 8,
	.data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};

/* Private function prototypes -----------------------------------------------*/

/**
  * @brief 
  * @param 
  * @retval 
  */
int can0_read(struct can_frame  *can_id)
{
		FD_ZERO(&fs_read0);
		FD_SET(fdcan0, &fs_read0);
		tv_timeout0.tv_sec = 0;
		tv_timeout0.tv_usec = WAIT_TIMEOUT;
		fs_sel0 = select(fdcan0+2, &fs_read0, NULL, NULL, &tv_timeout0);
		if(fs_sel0>0)
		{
			if(read(fdcan0, &frame0_rx, sizeof(frame0_rx)) >= 0)
			{
				memcpy(can_id->data, frame0_rx.data, 8);
				can_id->can_id = frame0_rx.can_id;
#ifdef TEST
				printf("rec:id[%x]	%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
					frame0_rx.can_id, frame0_rx.data[0],frame0_rx.data[1],frame0_rx.data[2],frame0_rx.data[3],frame0_rx.data[4],frame0_rx.data[5],frame0_rx.data[6],frame0_rx.data[7]);
#endif
			}
		}
		else if(fs_sel0 == 0)
		{
			// printf("can0:read timeout.\r\n");
			return 0;
		}
		else 
		{
			printf("can0:read error.\r\n");
			return -1;
		}
	return 1;
}

int can0_write(unsigned int can_id, const char tx_msg[8])
{
	int nbytes = 0;
	int x = 0;
	frame0_tx.can_id = can_id;
	memcpy(frame0_tx.data, tx_msg, 8);
	x = sizeof(struct can_frame);
	nbytes = write(fdcan0, &frame0_tx, x);
#ifdef TEST
	// printf("w0 x = %d nbytes = %d \r\n", x, nbytes);
#endif
		if(nbytes>0)
		{
			
#ifdef TEST
				printf("send:id[%x]	%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
					frame0_tx.can_id, frame0_tx.data[0],frame0_tx.data[1],frame0_tx.data[2],frame0_tx.data[3],frame0_tx.data[4],frame0_tx.data[5],frame0_tx.data[6],frame0_tx.data[7]);
#endif
			
		}
		else 
		{
			printf("Error writing to the file.\n");
			return -1;
		}

	return 1;
}


/* Private function prototypes -----------------------------------------------*/

/**
  * @brief 
  * @param 
  * @retval 
  */
int can0_rw(unsigned int can_id, const char tx_msg[8], char rx_msg[8])
{
	int nbytes = 0;
	int x = 0;
	frame0_tx.can_id = can_id;
	frame0_rx.can_id = can_id-0x80;
	// memcpy(frame0_tx.data, tx_msg, 8);
	x = sizeof(struct can_frame);
	// nbytes = write(fdcan0, &frame0_tx, x);
#ifdef TEST
	// printf("w0 x = %d nbytes = %d \r\n", x, nbytes);
#endif
	// if(x == nbytes)
	// {
		FD_ZERO(&fs_read0);
		FD_SET(fdcan0, &fs_read0);
		tv_timeout0.tv_sec = 0;
		tv_timeout0.tv_usec = WAIT_TIMEOUT;
		fs_sel0 = select(fdcan0+2, &fs_read0, NULL, NULL, &tv_timeout0);
		if(fs_sel0>0)
		{
			if(read(fdcan0, &frame0_rx, sizeof(frame0_rx)) >= 0)
			{
				memcpy(rx_msg, frame0_rx.data, 8);
#ifdef TEST
				printf("rec:id[%x]	%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
					frame0_rx.can_id, frame0_rx.data[0],frame0_rx.data[1],frame0_rx.data[2],frame0_rx.data[3],frame0_rx.data[4],frame0_rx.data[5],frame0_rx.data[6],frame0_rx.data[7]);
#endif
			}
		}
		else if(fs_sel0 == 0)
		{
			//printf("can0:timeout.\r\n");
			return 0;
		}
		else 
		{
			printf("can0:error.\r\n");
			return -1;
		}
	// }
	return 1;
}

/**
  * @brief 
  * @param 
  * @retval 
  */
int can1_rw(unsigned int can_id, const char tx_msg[8], char rx_msg[8])
{
	int nbytes = 0;
	int x = 0;
	frame1_tx.can_id = can_id;
	frame1_rx.can_id = can_id-0x80;
	memcpy(frame1_tx.data, tx_msg, 8);
	x = sizeof(struct can_frame);
	nbytes = write(fdcan1, &frame1_tx, x);
#ifdef TEST
	// printf("w1 x = %d nbytes = %d \r\n", x, nbytes);
#endif
	if(x == nbytes)
	{
		FD_ZERO(&fs_read1);
		FD_SET(fdcan1, &fs_read1);
		tv_timeout1.tv_sec = 0;
		tv_timeout1.tv_usec = WAIT_TIMEOUT;
		fs_sel1 = select(fdcan1+2, &fs_read1, NULL, NULL, &tv_timeout1);
		if(fs_sel1>0)
		{
			if(read(fdcan1, &frame1_rx, sizeof(frame1_rx)) >= 0)
			{
				memcpy(rx_msg, frame1_rx.data, 8);
#ifdef TEST
				printf("rec:id[%x]	%02x %02x %02x %02x %02x %02x %02x %02x\r\n",
					frame1_rx.can_id, frame1_rx.data[0],frame1_rx.data[1],frame1_rx.data[2],frame1_rx.data[3],frame1_rx.data[4],frame1_rx.data[5],frame1_rx.data[6],frame1_rx.data[7]);
#endif 
			}
		}
		else if(fs_sel1 == 0)
		{
			printf("can1:timeout.\r\n");
			return 0;
		}
		else 
		{
			printf("can1:error.\r\n");
			return -1;
		}
	}
	return 1;
}

/**
  * @brief 
  * @param 
  * @retval 
  */
int can_init(void)
{
	struct ifreq ifr;
    struct sockaddr_can addr;
    
    /* init can0 raw socket */
    if ((fdcan0 = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("socket(0)");
        return INADEQUATE_CONDITIONS;
    }

    /* get interface index */
    strcpy(ifr.ifr_name, "can0");
    ioctl(fdcan0, SIOCGIFINDEX, &ifr);
    addr.can_family  = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
#ifdef TEST	
    printf("%s at index %d\n", "can0", ifr.ifr_ifindex);
#endif
    if (bind(fdcan0, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind(0)");
        close(fdcan0);
        return INADEQUATE_CONDITIONS;
    }
	
	/* init can1 raw socket */
	if ((fdcan1 = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
        perror("socket(1)");
        return INADEQUATE_CONDITIONS;
    }
	
	/* get interface index */
	strcpy(ifr.ifr_name, "can1");
    ioctl(fdcan1, SIOCGIFINDEX, &ifr);
    addr.can_family  = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
#ifdef TEST
    printf("%s at index %d\n", "can1", ifr.ifr_ifindex);
#endif
	if (bind(fdcan1, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind(1)");
        close(fdcan1);
        return INADEQUATE_CONDITIONS;
    }
	
	usleep(WAIT_usDELAY);
	usleep(WAIT_usDELAY);
	return 0;
}
  
/**
  * @brief 
  * @param 
  * @retval 
  */
void can_deinit(void)
{
	close(fdcan0);
	//close(fdcan1);
}

/*============================================================================*/
#ifdef TEST
/**
  * @brief 
  * @param 
  * @retval 
  */
// int main(int argc, char *argv[])
// {
// 	int step=0;
// 	char tx_buf[8] = {'P', 'X', 0x00, 0x40, 0x00, 0x00, 0x00, 0x00};
// 	char rx_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
	
// 	can_init();
	
// 	while(1)
// 	{
// 		switch(step)
// 		{
// 			case 0:
// 				//can1_rw(0x301,tx_buf,rx_buf);
// 				can0_rw(0x304,tx_buf,rx_buf);
// 				step = 1;
// 				break;
// 			case 1:
// 				//can1_rw(0x302,tx_buf,rx_buf);
// 				can0_rw(0x305,tx_buf,rx_buf);
// 				step = 2;
// 				break;
// 			case 2:
// 				//can1_rw(0x303,tx_buf,rx_buf);
// 				can0_rw(0x306,tx_buf,rx_buf);	
// 				step = 0;
// 				break;
// 			default:
// 				break;
// 		}
// 	}
// 	can_deinit();
// }
#endif//TEST

/************************ (C) COPYRIGHT HopeMotion *****END OF FILE****/
